#include <PrefixTree.hpp>
#include <stdio.h>
#include <FTSSException.hpp>
#include <STLString.hpp>

PrefixTreeNode::PrefixTreeNode(UINT_32 node_id) : id_node(node_id){
	IDF = 0;
}

INT_32 PrefixTreeNode::GetNextNodeId(CCHAR_8 sym){
	/*UINT_16 sym_UINT = (UINT_16)sym;
	map<UINT_16, UINT_16>::iterator it = data.find(sym_UINT);
	if (it != data.end()){
		return (UINT_32)it->second;
	}*/
	//fprintf(stderr, "sym=%c\n", sym);
	for (INT_32 Ii = 0; Ii < ENGLISH_ALPHABET_SIZE + RUSSIAN_ALPHABET_SIZE; ++Ii){
		if ((data[Ii] >> 16) == sym){
			return data[Ii] & 0x0000FFFF;
		}
	}	
	return (INT_32)-1;
}

void PrefixTreeNode::PutNextNodeIdForSymbol(UINT_32 next_node_id, CCHAR_8 symbol){
	INT_32 Ii = 0;
	for (; Ii < ENGLISH_ALPHABET_SIZE + RUSSIAN_ALPHABET_SIZE && data[Ii]!=0; ++Ii){
        }
	data[Ii] = symbol << 16;
	data[Ii] += next_node_id;
	//fprintf(stderr, "add %d  %c %d\n", next_node_id << 16, symbol, data[Ii + 1] >> 16);
	//data[(UINT_16)symbol] = next_node_id;
	//printf(stderr, "current_node_id=%d, data[%d]=%d\n", id_node, symbol, data[(UINT_16)symbol]);
}


PrefixTreeNode::~PrefixTreeNode() throw (){
}

PrefixTree::PrefixTree(){
	size = 0;
	PrefixTreeNode *first_node = new PrefixTreeNode(0);
	nodes.push_back(first_node);
}


void  PrefixTree::AddWord(CCHAR_P word, UINT_32 IDF){
	UINT_16 current_ind = 0;
	PrefixTreeNode *current_node = *nodes.begin();
	while (word[current_ind] != '\0'){
		INT_32 node_ind = current_node->GetNextNodeId(word[current_ind]);
		if (node_ind == -1){
			PrefixTreeNode* new_node = new PrefixTreeNode(++size);
			nodes.push_back(new_node);
		//	fprintf(stderr, "BEFORE, new_node_ind=%d", new_node->id_node);
			current_node->PutNextNodeIdForSymbol(new_node->id_node, word[current_ind]);
			current_node = new_node;
			//fprintf(stderr, "AFTER, new_node_ind=%d", new_node->id_node);
		}else{
			current_node = nodes[node_ind];
		}
		//fprintf(stderr, "currrent_node_ind=%d", current_node->id_node);
		++current_ind;
	}
	if (current_node->IDF > 0){
		fprintf(stderr, "word %s already exist, IDF rewrited with new value =%u\n", word, IDF);
	}
	current_node->IDF = IDF;
}

void PrefixTree::RecursiveTour(UINT_32 id_node, string first_part_of_word){
	PrefixTreeNode *current_node = nodes[id_node];
	/*vector<PrefixTreeNode*>::iterator it = nodes.begin();
	while(it != nodes.end()){
		fprintf(stderr, "it->id=%d,id->IDF=%d\n", (*it)->id_node, (*it)->IDF);
		it++;
	}*/
	if (current_node->IDF > 0 && /*current_node->data.empty()*/ current_node->data[0] == 0) {
		fprintf(stdout, "\t%s\n", first_part_of_word.c_str());
	}else{
		if (current_node -> IDF > 0){
			fprintf(stdout, "\t%s\n", first_part_of_word.c_str());
		}
		/*map<UINT_16,UINT_16>::iterator it = current_node->data.begin(); 
		while(it != current_node->data.end()){
			//fprintf(stdout, "%c", it->first);i
			string tmp = first_part_of_word;
			tmp += it->first;
			RecursiveTour(it->second, tmp );
			it++;
		}*/
		INT_32 Ii = 0;
		for (; Ii < ENGLISH_ALPHABET_SIZE + RUSSIAN_ALPHABET_SIZE; ++Ii){
			if (current_node->data[Ii] != 0){
				CHAR_8 symb = current_node->data[Ii] >> 16;
 				INT_32 node_id = current_node->data[Ii] & 0x0000FFFF;
			//	fprintf(stderr, "current_node.id=%d, node_id=%d\n", current_node->id_node, node_id);
				string tmp = first_part_of_word;
				tmp += symb;
				RecursiveTour(node_id, tmp);
			}
		}
	}
}

void PrefixTree::GetHintsForWord(CCHAR_P word){
	UINT_16 current_ind = 0;
	PrefixTreeNode *current_node = *nodes.begin();
	fprintf(stdout, "all hints for word : %s : \n", word);
	while(word[current_ind] != '\0'){
		INT_32 node_ind = current_node->GetNextNodeId(word[current_ind]);
		if (node_ind == -1){
			fprintf(stderr, "prefix tree doen't have this word\n");
			return;
		}else{
			current_node = nodes[node_ind];
			//fprintf(stderr, "step to node_ind=%u\n", current_node->id_node);
		}
		++current_ind;
	}
	//fprintf(stderr, "currrent_node_ind=%u\n", current_node->id_node);
	RecursiveTour(current_node->id_node, string(word));
	
}

PrefixTree::~PrefixTree() throw (){
	vector<PrefixTreeNode*>::iterator it = nodes.begin();
	while(it != nodes.end()){
		delete *it;
		it++;
	}
}

/*int main(int argc, char **argv){
	if (argc < 2){
		fprintf(stderr, "usage: wordsfile\n" );
		PrefixTree pref;
		pref.AddWord("hui",1);
		pref.AddWord("huilo",1);
		pref.AddWord("hu",1);
		pref.AddWord("facepalm",1);
		pref.AddWord("facebook",1);
		
		string str = "";
		pref.RecursiveTour(0, str);
		return EX_USAGE;
		}
	fprintf(stderr, "it doesn't work with utf-8");
	PrefixTree *pref = new PrefixTree();
	UINT_32 currentIDF;
	CHAR_8 currentWord[MAX_WORD_LENGTH];
	FILE *f = fopen(argv[1], "r");
	fprintf(stderr, "here \n");
	UINT_32 Ii = 0;
	fprintf(stderr, "sizeof=%u\n", sizeof(PrefixTreeNode));
	while (!feof(f) && fscanf(f, "%u%s", &currentIDF, currentWord) && Ii < 10000){
		pref->AddWord(currentWord, currentIDF);
		fprintf(stdout, "%d - size of PrefixTree : #%u : %s with IDF=%u was added to prefix tree\n", pref->size, Ii, currentWord, currentIDF);
		++Ii;
	}
	string str = "";
	pref->RecursiveTour(0, str);
	delete pref;
	return EX_OK;
}*/
